namespace CloudNinja.Metering.Web.App_Start
{
    using System;
    using System.Configuration;
    using System.Web.Http;

    using CloudNinja.Metering.Authentication;
    using CloudNinja.Metering.Common.Logging;
    using CloudNinja.Metering.Data;
    using CloudNinja.Metering.Data.Dapper;
    using CloudNinja.Metering.Web.Authentication;

    using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
    using Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling;
    using Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.Configuration;
    using Microsoft.Practices.Unity;

    /// <summary>
    /// Specifies the Unity configuration for the main container.
    /// </summary>
    public class UnityConfig
    {
        #region Unity Container
        private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
        {
            var container = new UnityContainer();
            RegisterTypes(container);
            return container;
        });

        /// <summary>
        /// Gets the configured Unity container.
        /// </summary>
        public static IUnityContainer GetConfiguredContainer()
        {
            return container.Value;
        }
        #endregion

        /// <summary>Registers the type mappings with the Unity container.</summary>
        /// <param name="container">The unity container to configure.</param>
        /// <remarks>There is no need to register concrete types such as controllers or API controllers (unless you want to 
        /// change the defaults), as Unity allows resolving a concrete type even if it was not previously registered.</remarks>
        public static void RegisterTypes(IUnityContainer container)
        {
            var retryStrategy = new ExponentialBackoff(
                            5,
                            TimeSpan.FromSeconds(1),
                            TimeSpan.FromMinutes(1),
                            TimeSpan.FromSeconds(5));

            var sqlRetryPolicy = new RetryPolicy<SqlDatabaseTransientErrorDetectionStrategy>(retryStrategy);
            container.RegisterType<ILogger, AzureDiagnosticLogger>(new ContainerControlledLifetimeManager());

            var connStr = ConfigurationManager.ConnectionStrings["MeterDataRepository"].ConnectionString;

            container.RegisterType<IMeteringReporting, MeteringDataRepository>(
                new ContainerControlledLifetimeManager(),
                new InjectionConstructor(connStr, sqlRetryPolicy));

            container.RegisterType<IMeteringDataRepository, MeteringDataRepository>(
                new ContainerControlledLifetimeManager(),
                new InjectionConstructor(connStr, sqlRetryPolicy));

            container.RegisterType<IApiKeyStore, MeteringDataRepository>(
                new ContainerControlledLifetimeManager(),
                new InjectionConstructor(connStr, sqlRetryPolicy));

            container.RegisterType<IHmacHelper, HmacHelper>(new PerResolveLifetimeManager());

            container.RegisterInstance(
                typeof(HmacAuthHandler),
                new HmacAuthHandler(container.Resolve<IApiKeyStore>(), container.Resolve<IHmacHelper>()),
                new ContainerControlledLifetimeManager());
        }

        public static ILogger GetLogger()
        {
            return GetConfiguredContainer().Resolve<ILogger>();
        }

        public static IApiKeyStore GetApiKeyStore()
        {
            return GetConfiguredContainer().Resolve<IApiKeyStore>();
        }

        public static IHmacHelper GetHmacHelper()
        {
            return GetConfiguredContainer().Resolve<IHmacHelper>();
        }

        public static HmacAuthHandler GetHmacHandler(HttpConfiguration config)
        {
            var handler = (HmacAuthHandler)GetConfiguredContainer().Resolve(typeof(HmacAuthHandler));
            handler.SetHttpConfiguration(config);
            return handler;
        }
    }
}
